#![allow(unused_variables)]
#![allow(dead_code)]

use super::*;
use clap::{Subcommand, ValueEnum};
use const_format::formatcp;
use lazy_static::lazy_static;
use regex::Regex;
use std::io;
use std::path::PathBuf;
// use std::borrow::Cow;
pub mod collect;
pub mod connect;
mod misc;
pub mod screenshot;
pub mod shell;
use collect::CollectCmd;
use connect::{ConnectCmd, DisconnectCmd};
use misc::ListDevicesCmd;
use screenshot::ScreenshotCmdEx;
use shell::OutputShellCmd;
use shell::ShellCmd;

const ADB_BIN: &str = "adb";

pub static CMD_CHECK_ADB: PrequireCmd = PrequireCmd::new(
  ADB_BIN,
  "--version",
  Some(Link::new(
    "安装 ADB",
    "https://juejin.cn/post/7011002186641932324",
  )),
  Some(formatcp!(
    "Not found {0}!!\nPlease install {0} first.",
    ADB_BIN
  )),
);

#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)]
pub enum DeviceTypes {
  Android,
  IPhone,
}

#[derive(Debug, Subcommand)]
pub enum ADBComands {
  Collect,
  Connect {
    #[arg(
      short,
      long,
      value_name = "TYPE",
      require_equals = true,
      default_value_t = DeviceTypes::Android,
      default_missing_value = "android",
      value_enum
    )]
    device_type: DeviceTypes,

    #[arg(require_equals = true, value_parser = validate_socket)]
    socket: String,
  },
  Disconnect {
    #[arg(value_parser = validate_socket)]
    socket: Option<String>,
  },
  List,
}

pub fn serve_device(command: &ADBComands) {
  match command {
    ADBComands::Collect => {
      println!("device info collecting...");
      CollectCmd::new().exec();
    }
    ADBComands::Connect {
      device_type,
      socket,
    } => {
      println!("device connecting <{device_type:?}>device to {socket}");
      ConnectCmd::new(socket, None).exec();
    }
    ADBComands::Disconnect { socket } => {
      println!("device disconnecting {:?}", socket);
      DisconnectCmd::new(socket.as_ref().map_or(None, |v| Some(&*v)), None).exec();
    }
    ADBComands::List => {
      ListDevicesCmd::new().exec();
    }
  }
}

#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)]
pub enum ShowItems {
  CurrentFocus,
}

#[derive(Debug, Subcommand)]
pub enum PackageComands {
  Find {
    filter: String,
  },
  Monkey {
    pkg: String,
  },
  Screenshot {
    #[arg(short, long, default_value_t = 1, default_missing_value = "1")]
    num: usize,
    #[arg(
      short,
      long,
      default_value_t = String::from("."),
      default_missing_value = "."
    )]
    out_dir: String,
    pkg: String,
  },
  Show {
    #[arg(value_enum)]
    item: ShowItems,
  },
  Start {
    pkg: String,
  },
}

pub fn serve_package(command: &PackageComands) {
  match command {
    PackageComands::Find { filter } => {
      ShellCmd::new(&["pm", "list", "packages", "-3", &*filter], None)
        .exec()
        .expect("PackageComands Find fail");
    }
    PackageComands::Monkey { pkg } => {
      ShellCmd::new(
        &["monkey -p", pkg, "-v 1 | grep component="],
        Some(Box::new(|s| {
          lazy_static! {
            static ref RE: Regex = Regex::new(r"component=(.*);end").unwrap();
          }
          for cap in RE.captures_iter(&s) {
            return cap[1].to_string();
          }
          String::from(s)
        })),
      )
      .exec()
      .expect("PackageComands Monkey fail");
    }
    PackageComands::Screenshot { num, out_dir, pkg } => {
      // println!("num:{num}, out_dir:{out_dir}");
      if let Ok(success) = ScreenshotCmdEx::new(pkg, *num, &PathBuf::from(&out_dir)).exec() {
        if success {
          println!("截图成功保存在{out_dir}!");
        }
      }
    }
    PackageComands::Show { item } => match item {
      ShowItems::CurrentFocus => {
        ShellCmd::new(&["dumpsys window | grep mCurrentFocus"], None)
          .exec()
          .expect("PackageComands Show fail");
      }
    },
    PackageComands::Start { pkg } => {
      start_app(pkg).expect("PackageComands Start fail");
    }
  }
}

pub fn start_app(pkg: &str) -> io::Result<()> {
  ShellCmd::new(
    &["monkey -p", pkg, "-v 1 | grep component="],
    Some(Box::new(|s| {
      lazy_static! {
        static ref RE: Regex = Regex::new(r"component=(.*);end").unwrap();
      }
      for cap in RE.captures_iter(&s) {
        if let Err(err) = ShellCmd::new(&["am", "start", &cap[1]], None).exec() {
          eprintln!("start app fail:{}", err)
        }
        break;
      }
      String::from("")
    })),
  )
  .exec()
}

pub fn tap(x: u32, y: u32) -> io::Result<bool> {
  ShellCmd::new(
    &["input tap", &x.to_string(), &y.to_string()],
    Some(Box::new(|_| String::from(""))),
  )
  .exec()?;
  Ok(true)
}

pub fn get_default_keyboard() -> io::Result<String> {
  OutputShellCmd::new(&["settings get secure default_input_method"]).exec()
}

pub fn switch_keyborad(keyborad: &str) -> io::Result<()> {
  // adb shell ime set com.sohu.inputmethod.sogou.xiaomi/.SogouIME
  ShellCmd::new(
    &["ime set", keyborad],
    None,
    // Some(Box::new(|_| String::from(""))),
  )
  .exec()
}

pub fn switch_to_adb_keyborad() -> io::Result<()> {
  switch_keyborad("com.android.adbkeyboard/.AdbIME")
}

pub fn text(msg: &str) -> io::Result<bool> {

  ShellCmd::new(
    &[
      "am broadcast -a ADB_INPUT_B64 --es msg `echo -n '",
      msg,
      "' | base64`",
    ],
    Some(Box::new(|_| String::from(""))),
  )
  .exec()?;

  Ok(true)
}

pub fn keycode(code: u8) -> io::Result<bool> {
  ShellCmd::new(
    &[
      "am broadcast -a ADB_EDITOR_CODE --ei code",
      &code.to_string(),
    ],
    Some(Box::new(|_| String::from(""))),
  )
  .exec()?;
  Ok(true)
}

pub fn keycode2(code: u8) -> io::Result<bool> {
  ShellCmd::new(
    &["input keyevent", &code.to_string()],
    Some(Box::new(|_| String::from(""))),
  )
  .exec()?;
  Ok(true)
}

pub fn swipe(from: u32, to: u32) -> io::Result<bool> {
  ShellCmd::new(
    &["input swipe 600", &from.to_string(), "600", &to.to_string()],
    Some(Box::new(|_| String::from(""))),
  )
  .exec()?;
  Ok(true)
}

// fn process_cmd_output<T: AsRef<str>>(output: Output, warning_check_strs: Option<&[T]>) {
//   let mut print_output = true;
//   if !output.status.success() {
//     let stderr = String::from_utf8(output.stderr).unwrap();
//     eprintln!("{}", stderr.red());
//   } else {
//     let output = String::from_utf8(output.stdout).unwrap();
//     if let Some(warning_check_strs) = warning_check_strs {
//       for warning_check_str in warning_check_strs {
//         match output.find(warning_check_str.as_ref()) {
//           Some(_) => {
//             eprintln!("{}", output.yellow());
//             return;
//           }
//           None => {
//             print_output = print_output && true;
//           }
//         };
//       }
//     } else {
//       print_output = true;
//     }

//     if print_output {
//       println!("{}", output.green());
//     }
//   }
// }

// fn print_cmd_output(output: Output) {
//   let output = String::from_utf8(output.stdout).unwrap();
//   println!("{}", output.green());
// }
